﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Unity.Mvc3;
using BootCms.Environment;
using BootCms.Caching;
using NHibernate;
using FluentNHibernate.Automapping;
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using NHibernate.Tool.hbm2ddl;
using NHibernate.Cfg;
using Microsoft.Practices.Unity;

namespace BootCms
{
    public static class BootConfig
    {
        public static void Init()
        {
            var container = Build();
            DependencyResolver.SetResolver(new UnityDependencyResolver(container));
        }

        private static Configuration CreateConfig()
        {
            return Fluently.Configure()
                .Database(DatabaseConfig)
                .Mappings(m => m.AutoMappings.Add(AutoMap.Assembly(typeof(IDependency).Assembly)
                .Where(IsEntity)))
                .ExposeConfiguration(ValidateSchema)
                .ExposeConfiguration(BuildSchema)
                .BuildConfiguration();
        }

        private static IPersistenceConfigurer DatabaseConfig()
        {
            return MsSqlConfiguration.MsSql2008
                .UseOuterJoin()
                .ConnectionString(x => x.FromConnectionStringWithKey("BootCmsConnectionString"))
                .ShowSql();
        }

        public static void ValidateSchema(Configuration config)
        {
            var check = new SchemaValidator(config);
        }


        private static void BuildSchema(Configuration config)
        {
            new SchemaUpdate(config).Execute(false, true);
            SchemaMetadataUpdater.QuoteTableAndColumns(config);
        }

        private static bool IsEntity(Type t)
        {
            return typeof(IDependency).IsAssignableFrom(t);
        }

        public static UnityContainer Build()
        {
            var conf = CreateConfig();
            var builder = new UnityContainer();

            builder.RegisterType<HttpContextBase, HttpContextWrapper>(new InjectionConstructor(HttpContext.Current))

            .RegisterType<ISessionFactory>("tenant_session_factory",
                new ContainerControlledLifetimeManager(),
                new InjectionFactory(c => conf.BuildSessionFactory()))

            .RegisterType<ISession>("tenant_session",
                new PerRequestLifetimeManager(),
                new InjectionFactory(c => c.Resolve<ISessionFactory>("tenant_session_factory").OpenSession()))

            .RegisterType<ITenantRepository, NHibernateTenantRepository>()
                .RegisterType<NHibernateTenantRepository>(
                new InjectionConstructor(
                    new ResolvedParameter<ISession>("tenant_session"),
                    new ResolvedParameter<HttpContextBase>()))

            .RegisterType<ISessionFactory>(
                new PerHostLifetimeManager(() => new HttpContextWrapper(HttpContext.Current)),
                new InjectionFactory(c =>
                {
                    var connString = c
                        .Resolve<ITenantRepository>()
                        .Current
                        .ConnectionString;
                    return conf.SetProperty(NHibernate.Cfg.Environment.ConnectionString, connString)
                        .BuildSessionFactory();
                }))

            .RegisterType<ISession>(new PerRequestLifetimeManager(), new InjectionFactory(c => c.Resolve<ISessionFactory>().OpenSession()));

            return builder;
        }
    }
}